{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第二章 面向对象编程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一些原则：\n",
    "\n",
    "1. 类应该以首字母大写的单数形式的名词来命名，如果是多个单词，使用`驼峰命名法`。\n",
    "2. 函数包括类的方法，命名应该小写，一般用描述作用的动词来命名，如果返回的值直接可用名词描述，那就用名词命名。多个单词用`下划线命名法`。\n",
    "3. 对变量命名包括实例变量，一般为小写的名词。\n",
    "4. 常量命名一般是大写单词，并用`下划线命名法`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以单下划线开头的标识符，一般意味着只为类或者模块内部使用，不作为公共接口。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "块注释：三个单引号或者三个双引号，且需要放在模块、类、函数主体第一个语句才能被识别为注释（docstring），否则为多行字符串并报错。事实上，help文档就是调出了函数的docstring。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "面向对象编程设计：将工作分为不同角色（这些角色将成为不同的类），不同角色有不同的responsibility（这些责任决定了类的方法），然后就是不同对象协同工作（不同类之间如何合作）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "CreditCard类（信用卡类）：每张银行卡都是一个实例，不同银行卡一般有不同的实例变量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "code_folding": []
   },
   "outputs": [],
   "source": [
    "class CreditCard:\n",
    "    \n",
    "    def __init__(self, customer, bank, acnt, limit):    ## 每个实例存储的实例变量，反映其当前状态，这个函数称为类的构造函数\n",
    "        self._customer = customer                       ## 初始化，实例变量传入\n",
    "        self._bank = bank\n",
    "        self._account = acnt                            ## 标识符不一样，一个为形式参数，一个是之后调用的\n",
    "        self._limit = limit\n",
    "        self._balance = 0                               ## 初始化不一定与传入参数完全一致，可以做一定处理，只要之后很多方法需要，那就先定义\n",
    "        \n",
    "    def get_customer(self):                             ## 这个self理解为调用我们之前初始化的实例变量，当然也可以多定义一些其他的参数\n",
    "        return self._customer\n",
    "    \n",
    "    def get_bank(self):\n",
    "        return self._bank\n",
    "    \n",
    "    def get_account(self):\n",
    "        return self._account\n",
    "    \n",
    "    def get_limit(self):\n",
    "        return self._limit \n",
    "    \n",
    "    def get_balance(self):\n",
    "        return self._balance\n",
    "    \n",
    "    def charge(self, price):                             ## 这个price是在调用实例（如信用卡充值了，应该增加余额）时输入的外界变量\n",
    "        if price + self._balance > self._limit:          ## 充值加余额不能查过信用额度\n",
    "            return False\n",
    "        else:\n",
    "            self._balance += price                       ## 这里改变了实例变量，也是之所以前面被称为初始化的原因\n",
    "            return True\n",
    "        \n",
    "    def make_payment(self, amount):\n",
    "        self._balance -= amount    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在调用实例方法时，并不需要输入self，因为Python解释器会自动将前面的实例名称绑定为self，所以说self在类的定义中充当实例的标识符。下面来创建一个实例："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [],
   "source": [
    "cc = CreditCard('John Doe', '1st Bank', '5391 0375 9387 5309', 1000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`__init__`方法称为类的构造函数，作用\"承上启下\"，既规定实例变量，也规定了类的实例对实例变量如何调用，是从外到内，也是后续定义其他方法的基础。`self._balance`中的下划线表示这个实例变量是不可直接访问的（非公有的 nonpublic），也不可直接更改的，只能通过类定义的方法进行更改，想获取这个实例的变量的值，也只能通过方法来return，否则，每一张信用卡都可以随意更改为无限大的余额，这显然是不行的，通过充值和消费（信用卡类的两个方法）来更改余额才是合理的。（然而事实上，这个下划线只是表明这个意思，却没有实际限制`cc._balance`来访问或者`cc._balance = 1`来赋值等语句的执行）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "类的实例间的运算符如`+`、`-`、`*`等可以通过特别方法赋予特殊的含义（比如内置类list，`+`就通过特殊方法定义为连接）。例如可以通过在类中定义`__add__()`方法来定义类的实例之间的加减，比如`a+b`相当于`a.__add__(b)`或者`b.__radd__(a)`，即可以是左边的类定义了`__add__()`方法（先看左边），也可以是右边的类定义了`__radd__()`方法。类似的特殊方法还有很多。通过类的特殊方法可以定义类的实例之间的运算。（运算符左右交换可能产生不同的结果）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "顶层函数或者一些类如`str()`、`len()`等，在运行`str(foo)`，`len(foo)`时（foo是类的实例），其实是调用了foo这个实例对应的类的方法`foo.__str__()`和`foo.__len__()`，相当于类本身给定这些特殊的顶层函数或者常用的类对应的方法，当上面形式的代码运行时，直接调用类定义的方法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面给出一个Vector类，实现一些特殊的方法（如定义与列表不同的__add__()方法，最终定义的其实类似于R语言的向量）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Vector:\n",
    "    \n",
    "    def __init__(self, d):                 ## d是一个正整数\n",
    "        self._coords = [0]*d               ## 最终是调用了list类的一个实例，这里初始化就不是d，而是d维列表\n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self._coords)           ## 仍然使用list长度的概念，注意self._coords是list，但self不是list，而是实例\n",
    "    \n",
    "    def __getitem__(self, j):              ## 访问第j个元素，用__getitem__方法定义，一些不符合规范的，但符合理解往往都有特殊方法\n",
    "        return self._coords[j]\n",
    "    \n",
    "    def __setitem__(self, j, val):         ## 修改第j个元素的值\n",
    "        self._coords[j] = val              ## 在这里不要考虑变量的作用域什么的，很乱\n",
    "\n",
    "    def __add__(self, other):              ## 定义实例之间的和运算\n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       ## ValueError是一个异常类，其中应该是定义了raise的特殊方法\n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] + other[j]\n",
    "        return result\n",
    "    \n",
    "    def __eq__(self, other):                ## 相等的定义套用list的定义\n",
    "        return self._coords == other._coords \n",
    "    \n",
    "    def __ne__(self, other):\n",
    "        return not self == other\n",
    "    \n",
    "    def __str__(self):                      ## print(..)或者str(..)时会调用，只要print就一定是先转化为字符\n",
    "        return '<' + str(self._coords)[1:-1] + '>'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "45\n",
      "<0, 46, 0, 0, 90>\n"
     ]
    }
   ],
   "source": [
    "v = Vector(5)\n",
    "v[1] = 23\n",
    "v[-1] = 45\n",
    "print(v[4])\n",
    "u = v + v\n",
    "print(u)\n",
    "total = 0\n",
    "for i in v:          ## 只要有__getitem__和__len__就可以迭代\n",
    "    total += i"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[点击跳转到迭代器和生成器](https://www.cnblogs.com/lvcm/p/9372622.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "list、tuple、dict、set等容器之所以是`iterable`的，是因为在使用`for ... in ...`时，会自动调用这些类里面的`__iter__`方法，将可迭代对象转化为迭代器，而迭代器的协议就是拥有`__next__`方法，可以访问下一个元素，而`for ... in ...`第二次发挥了作用，会自动不断地调用`__next__`方法直至`raise StopIteration`，因此完成了迭代。正常来讲，要生成一个迭代器，需要定义`__iter__`方法，而生成器是一种生成迭代器的捷径，生成器可以直接生成迭代器。有两种方法可以构造生成器，一种是将列表解析（也叫列表生成式）的`[]`换成`()`，好处是如果生成的列表只起迭代作用，那么用生成器生成的迭代器来迭代可以节省内存。另一种方法是将函数的`return`换成`yield`，不过要注意，一般需要有多个`yield`或者写个`for`、`while`来多次`yield`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "生成器的执行步骤：每次调用`next()`的时候开始执行，到`yield`返回，下次调用`next()`的时候从上次`yield`之后继续执行，直到下一个`yield`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可迭代对象（iterable）必须实现`__iter__()`方法。\n",
    "\n",
    "迭代器（iterator）必须实现`__iter__()`和`__next__()`方法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "list占用内存而生成器或者迭代器不会：因为list是一次性存储所有数，而生成器和迭代器是每次`next()`才计算下一个，不需要存储所有的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "自定义Range类，要求支持`__len__()`和`__getitem__()`方法，从而可以直接用`len()`和`[k]`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Range:\n",
    "    \n",
    "    def __init__(self, start, stop=None, step=1):\n",
    "        if step == 0:\n",
    "            raise ValueError('step cannot be 0')\n",
    "        if stop is None:\n",
    "            start, stop = 0, start\n",
    "        self._length = max(0, (stop - start + step - 1)//step)         ## 通过实例变量计算长度\n",
    "        self._start = start\n",
    "        self._stop = stop\n",
    "        self._step = step\n",
    "    \n",
    "    def __len__(self):\n",
    "        return self._length\n",
    "    \n",
    "    def __getitem__(self, k):\n",
    "        if k < 0:\n",
    "            k += len(self)\n",
    "        if not 0 <= k < self._length:\n",
    "            raise IndexError('index out of range')\n",
    "        return self._start + k*self._step                              ## 仍然是通过实例变量计算"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "50\n",
      "25\n"
     ]
    }
   ],
   "source": [
    "a = Range(1, 100, 2)\n",
    "print(len(a))\n",
    "print(a[12])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "继承：子类（subclass、child class）可以继承父类（parent class、也称为基类 base class、超类 superclass）的实例变量（在初始化时需要一行代码加载）和方法，还可以定义自己的方法或者定义与父类相同名称的方法（会覆盖父类的该方法），父类的初始化往往是子类初始化的一部分。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PredatoryCreditCard(CreditCard):\n",
    "    \n",
    "    def __init__(self, customer, bank, acnt, limit, apr):\n",
    "        super().__init__(customer, bank, acnt, limit)              ## 引用父类的初始化\n",
    "        self._apr = apr\n",
    "    \n",
    "    def charge(self, price):                                       ## 覆盖父类的方法\n",
    "        success = super().charge(price)\n",
    "        if not success:\n",
    "            self._balance -= 5\n",
    "        return success\n",
    "    \n",
    "    def process_month(self):\n",
    "        if self._balance > 0:\n",
    "            monthly._factor = pow(1 + self._apr, 1/12)\n",
    "            self._balance *= monthly._factor"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面先实现一个数列（progression）类，然后分别实现等差数列、等比数列和斐波那契数列三个子列。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Progression类是一个迭代器（定义了两个特殊方法：`__iter__()`和`__next__()`），从某个数开始，默认为无穷数列，并定义了查看后面n个数的方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "code_folding": []
   },
   "outputs": [],
   "source": [
    "class Progression:\n",
    "    \n",
    "    def __init__(self, start = 0):\n",
    "        self._current = start\n",
    "    \n",
    "    def _advance(self):                        ## 这个其实可以去掉，但是有这个方便之后其他数列的__next__()\n",
    "        self._current += 1\n",
    "    \n",
    "    def __next__(self):\n",
    "        if self._current is None:\n",
    "            raise StopIteration()\n",
    "        else:\n",
    "            answer = self._current\n",
    "            self._advance()\n",
    "            return answer\n",
    "    \n",
    "    def __iter__(self):\n",
    "        return self\n",
    "    \n",
    "    def print_progression(self, n):\n",
    "        print(' '.join(str(next(self)) for j in range(n)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1 2 3 4 5 6 7 8 9 10\n",
      "11\n"
     ]
    }
   ],
   "source": [
    "pp = Progression()\n",
    "print(next(pp))\n",
    "pp.print_progression(10)\n",
    "print(next(pp))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "等差数列类（依然是一个迭代器）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ArithmeticProgression(Progression):\n",
    "    \n",
    "    def __init__(self, increment = 1, start = 0):\n",
    "        super().__init__(start)                        ## 父类初始化要加入参数\n",
    "        self._increment = increment\n",
    "        \n",
    "    def _advance(self):\n",
    "        self._current += self._increment"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "5 9 13 17 21 25 29 33 37 41\n",
      "45\n"
     ]
    }
   ],
   "source": [
    "ap = ArithmeticProgression(4, 1)\n",
    "print(next(ap))\n",
    "ap.print_progression(10)\n",
    "print(next(ap))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "等比数列类（还是一个迭代器）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {},
   "outputs": [],
   "source": [
    "class GeometricProgession(Progression):\n",
    "    \n",
    "    def __init__(self, base = 2, start = 1):\n",
    "        super().__init__(start)\n",
    "        self._base = base\n",
    "        \n",
    "    def _advance(self):\n",
    "        self._current *= self._base"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "6 18 54 162 486 1458 4374 13122 39366 118098\n",
      "354294\n"
     ]
    }
   ],
   "source": [
    "gp = GeometricProgession(3, 2)\n",
    "print(next(gp))\n",
    "gp.print_progression(10)\n",
    "print(next(gp))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "斐波那契数列类（还是一个迭代器）："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "class FibonacciProgression(Progression):\n",
    "    \n",
    "    def __init__(self, first = 0, second = 1):\n",
    "        super().__init__(first)\n",
    "        self._prev = second - first\n",
    "        \n",
    "    def _advance(self):\n",
    "        self._prev, self._current = self._current, self._prev + self._current"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1 1 2 3 5 8 13 21 34 55\n",
      "89\n"
     ]
    }
   ],
   "source": [
    "fp = FibonacciProgression()\n",
    "print(next(fp))\n",
    "fp.print_progression(10)\n",
    "print(next(fp))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "迭代器和生成器例子："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "按协议实现一个迭代器：首先有`__next__()`方法从而支持`next()`函数，然后有`__iter__()`方法，从而支持`for`循环（即iterable）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {},
   "outputs": [],
   "source": [
    "class count():\n",
    "    \n",
    "    def __init__(self, start, stop):\n",
    "        self._current = start\n",
    "        self._stop = stop\n",
    "        \n",
    "    def __next__(self):\n",
    "        if self._current < self._stop:\n",
    "            a = self._current\n",
    "            self._current += 1\n",
    "            return a\n",
    "        else:\n",
    "            raise StopIteration()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'count' object is not iterable",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-115-6eccfa4d1fc2>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mcount\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m10\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      2\u001b[0m     \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mTypeError\u001b[0m: 'count' object is not iterable"
     ]
    }
   ],
   "source": [
    "for i in count(1, 10):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 121,
   "metadata": {},
   "outputs": [],
   "source": [
    "class count():\n",
    "    \n",
    "    def __init__(self, start, stop):\n",
    "        self._current = start\n",
    "        self._stop = stop\n",
    "        \n",
    "    def __next__(self):\n",
    "        if self._current <= self._stop:\n",
    "            a = self._current\n",
    "            self._current += 1\n",
    "            return a\n",
    "        else:\n",
    "            raise StopIteration()\n",
    "    \n",
    "    def __iter__(self):\n",
    "        return self"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 122,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n",
      "6\n",
      "7\n",
      "8\n",
      "9\n",
      "10\n"
     ]
    }
   ],
   "source": [
    "for i in count(1, 10):\n",
    "    print(i)                                ## __next__()返回什么，就print什么"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用`yield`实现生成器，从而在for循环中自动生成迭代器。生成器也可以将列表生成式换成圆括号来实现。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 119,
   "metadata": {},
   "outputs": [],
   "source": [
    "def count(start, stop):\n",
    "    for i in range(start, stop + 1):\n",
    "        yield i"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 120,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n",
      "6\n",
      "7\n",
      "8\n",
      "9\n",
      "10\n"
     ]
    }
   ],
   "source": [
    "for i in count(1, 10):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "抽象基类：一个类的唯一目的是作为继承用的父类（基类、超类），就成为抽象基类。抽象基类是不能实例化的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于在每一个类的实例中都相同的值，如果放在`__init__(...)`中进行初始化，则会进入每一个类的实例的命名空间造成浪费，因此可以将常量放在`__init__(...)`之前直接进行定义，如\n",
    "\n",
    "````\n",
    "class Example():\n",
    "    \n",
    "    a = 1\n",
    "```\n",
    "\n",
    "在类内调用时，用`Example.a`，即用类调用类命名空间（一般存储的是类的方法）中的常数，而不是用实例（实例命名空间中存储的是实例变量值）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "为什么子类定义与父类相同方法的名称会覆盖父类的方法：在使用点操作符调用时，会先搜索子类实例命名空间，然后子类命名空间然后父类命名空间、父类的父类......因为会先在子类的命名空间中搜索到方法，所以相当于覆盖了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3]\n",
      "[1, 2, 3]\n"
     ]
    }
   ],
   "source": [
    "import copy\n",
    "\n",
    "mylist = [1, 2, 3]\n",
    "mylist_1 = copy.copy(mylist)                      ## 浅拷贝\n",
    "mylist_2 = copy.deepcopy(mylist)                  ## 深拷贝\n",
    "print(mylist_1)\n",
    "print(mylist_2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "练习："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-2.4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Flower:\n",
    "    \n",
    "    def __init__(self, name, number, price):\n",
    "        self._name = name\n",
    "        self._num = number\n",
    "        self._price = price\n",
    "    \n",
    "    def get_name(self):\n",
    "        return self._name\n",
    "    \n",
    "    def get_number(self):\n",
    "        return self._num\n",
    "    \n",
    "    def get_price(self):\n",
    "        return self._price"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "rose\n",
      "100\n",
      "10\n"
     ]
    }
   ],
   "source": [
    "flower = Flower('rose', 100, 10)\n",
    "\n",
    "print(flower.get_name())\n",
    "print(flower.get_number())\n",
    "print(flower.get_price())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-2.6"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "class CreditCard:\n",
    "    \n",
    "    def __init__(self, customer, bank, acnt, limit):    \n",
    "        self._customer = customer                       \n",
    "        self._bank = bank\n",
    "        self._account = acnt                           \n",
    "        self._limit = limit\n",
    "        self._balance = 0                               \n",
    "        \n",
    "    def get_customer(self):                             \n",
    "        return self._customer\n",
    "    \n",
    "    def get_bank(self):\n",
    "        return self._bank\n",
    "    \n",
    "    def get_account(self):\n",
    "        return self._account\n",
    "    \n",
    "    def get_limit(self):\n",
    "        return self._limit \n",
    "    \n",
    "    def get_balance(self):\n",
    "        return self._balance\n",
    "    \n",
    "    def charge(self, price):                             \n",
    "        if price + self._balance > self._limit:          \n",
    "            return False\n",
    "        else:\n",
    "            self._balance += price                       \n",
    "            return True\n",
    "        \n",
    "    def make_payment(self, amount):\n",
    "        if amount < 0:\n",
    "            raise ValueError('Amount should be positive!')          ## raise用于自定义抛出异常，抛出异常后之后的代码不会再运行\n",
    "        self._balance -= amount  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000\n"
     ]
    },
    {
     "ename": "ValueError",
     "evalue": "Amount should be positive!",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-48-0116bf6ef5be>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      3\u001b[0m \u001b[0mcreditcard\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcharge\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1000\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcreditcard\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_balance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mcreditcard\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmake_payment\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      6\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcreditcard\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_balance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m<ipython-input-47-ddd5ab445337>\u001b[0m in \u001b[0;36mmake_payment\u001b[1;34m(self, amount)\u001b[0m\n\u001b[0;32m     32\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mmake_payment\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mamount\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     33\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mamount\u001b[0m \u001b[1;33m<\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 34\u001b[1;33m             \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Amount should be positive!'\u001b[0m\u001b[1;33m)\u001b[0m          \u001b[1;31m## raise用于自定义抛出异常，抛出异常后之后的代码不会再运行\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     35\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_balance\u001b[0m \u001b[1;33m-=\u001b[0m \u001b[0mamount\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mValueError\u001b[0m: Amount should be positive!"
     ]
    }
   ],
   "source": [
    "creditcard = CreditCard('John Bowman', 'California Savings', '5391 0375 9387 5309', 2500)\n",
    "\n",
    "creditcard.charge(1000)\n",
    "print(creditcard.get_balance())\n",
    "creditcard.make_payment(-10)\n",
    "print(creditcard.get_balance())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`try-except-else-finally`与`raise`的区别在于，前者根据Python可能出现的内置错误类实例进行不同的处理，如果发生错误不会一股脑直接停止，也不会直接打印原来的错误信息，而是运行except模块的语句，运行完语句之后，该循环的将继续循环；`raise`用于人为地抛出异常，主要针对语法上无错误但是理解上有错误的输入或者代码等，个人认为也可以`print`一句错误信息来判断。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`raise`产生的异常也会进入`except`，因此二者可以结合使用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`try-except-else-finally`可以使异常不向上传播直接中断运行，造成损失。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`raise`一般与条件语句配合使用，指出在什么情况下抛出什么异常，然后再用`try-except`语句处理，防止异常直接使程序中断。那为什么还要`raise`，而不是一开始条件语句用`print`呢？因为`raise`引发异常可以与Python正常引发的异常统一化处理，使用`try-except`语句。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-2.7"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [],
   "source": [
    "class CreditCard:\n",
    "    \n",
    "    def __init__(self, customer, bank, acnt, limit, balance = 0):    \n",
    "        self._customer = customer                       \n",
    "        self._bank = bank\n",
    "        self._account = acnt                           \n",
    "        self._limit = limit\n",
    "        self._balance = balance                               \n",
    "        \n",
    "    def get_customer(self):                             \n",
    "        return self._customer\n",
    "    \n",
    "    def get_bank(self):\n",
    "        return self._bank\n",
    "    \n",
    "    def get_account(self):\n",
    "        return self._account\n",
    "    \n",
    "    def get_limit(self):\n",
    "        return self._limit \n",
    "    \n",
    "    def get_balance(self):\n",
    "        return self._balance\n",
    "    \n",
    "    def charge(self, price):                             \n",
    "        if price + self._balance > self._limit:          \n",
    "            return False\n",
    "        else:\n",
    "            self._balance += price                       \n",
    "            return True\n",
    "        \n",
    "    def make_payment(self, amount):\n",
    "        if amount <= 0:\n",
    "            print('Amount should be positive.')                 ## 如果不需要统一处理异常，一般还是print一下就好，raise得与try配合才行\n",
    "        else:\n",
    "            self._balance -= amount  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000\n",
      "0\n"
     ]
    }
   ],
   "source": [
    "creditcards = []\n",
    "\n",
    "creditcards.append(CreditCard('John Bowman', 'California Savings', '5391 0375 9387 5309', 2500, 1000))\n",
    "creditcards.append(CreditCard('John Bowman', 'California Savings', '5391 0375 9387 5309', 2500))\n",
    "\n",
    "print(creditcards[0].get_balance())\n",
    "print(creditcards[1].get_balance())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-2.8"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Vector:\n",
    "    \n",
    "    def __init__(self, d):                 \n",
    "        self._coords = [0]*d               \n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self._coords)         \n",
    "    \n",
    "    def __getitem__(self, j):              \n",
    "        return self._coords[j]\n",
    "    \n",
    "    def __setitem__(self, j, val):         \n",
    "        self._coords[j] = val           \n",
    "\n",
    "    def __add__(self, other):            \n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] + other[j]\n",
    "        return result\n",
    "    \n",
    "    def __sub__(self, other):\n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] - other[j]\n",
    "        return result\n",
    "    \n",
    "    def __eq__(self, other):                \n",
    "        return self._coords == other._coords \n",
    "    \n",
    "    def __ne__(self, other):\n",
    "        return not self == other\n",
    "    \n",
    "    def __str__(self):                     \n",
    "        return '<' + str(self._coords)[1:-1] + '>'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<1, 2, 3, 4, 5>\n",
      "<1, 4, 9, 16, 25>\n",
      "<0, -2, -6, -12, -20>\n"
     ]
    }
   ],
   "source": [
    "vectors = []\n",
    "\n",
    "vectors.append(Vector(5))\n",
    "vectors.append(Vector(5))\n",
    "\n",
    "for i in range(1, 6):\n",
    "    vectors[0][i-1] = i\n",
    "    vectors[1][i-1] = i**2\n",
    "\n",
    "print(vectors[0])\n",
    "print(vectors[1])\n",
    "print(vectors[0]-vectors[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-2.10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Vector:\n",
    "    \n",
    "    def __init__(self, d):                 \n",
    "        self._coords = [0]*d               \n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self._coords)         \n",
    "    \n",
    "    def __getitem__(self, j):              \n",
    "        return self._coords[j]\n",
    "    \n",
    "    def __setitem__(self, j, val):         \n",
    "        self._coords[j] = val           \n",
    "\n",
    "    def __add__(self, other):            \n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] + other[j]\n",
    "        return result\n",
    "    \n",
    "    def __sub__(self, other):\n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] - other[j]\n",
    "        return result\n",
    "    \n",
    "    def __eq__(self, other):                \n",
    "        return self._coords == other._coords \n",
    "    \n",
    "    def __ne__(self, other):\n",
    "        return not self == other\n",
    "    \n",
    "    def __str__(self):                     \n",
    "        return '<' + str(self._coords)[1:-1] + '>'\n",
    "    \n",
    "    def __neg__(self):\n",
    "        result = Vector(len(self))\n",
    "        for i in range(len(self)):\n",
    "            result[i] = -self[i]                                        ## 前面已经定义了__getitem__，这里直接用slef[i]没有问题\n",
    "        return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<0, 5, 0, 0, 4>\n",
      "<0, -5, 0, 0, -4>\n"
     ]
    }
   ],
   "source": [
    "vector = Vector(5)\n",
    "vector[1] = 5\n",
    "vector[-1] = 4\n",
    "\n",
    "print(vector)\n",
    "print(-vector)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-2.11"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "让list的`__add__`方法中允许`list + vector`的存在。一般来讲会先看左边的类是否有定义，才会看右边的类`__radd__`的定义。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-2.12"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Vector:\n",
    "    \n",
    "    def __init__(self, d):                 \n",
    "        self._coords = [0]*d               \n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self._coords)         \n",
    "    \n",
    "    def __getitem__(self, j):              \n",
    "        return self._coords[j]\n",
    "    \n",
    "    def __setitem__(self, j, val):         \n",
    "        self._coords[j] = val           \n",
    "\n",
    "    def __add__(self, other):            \n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] + other[j]\n",
    "        return result\n",
    "    \n",
    "    def __sub__(self, other):\n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] - other[j]\n",
    "        return result\n",
    "    \n",
    "    def __eq__(self, other):                \n",
    "        return self._coords == other._coords \n",
    "    \n",
    "    def __ne__(self, other):\n",
    "        return not self == other\n",
    "    \n",
    "    def __str__(self):                     \n",
    "        return '<' + str(self._coords)[1:-1] + '>'\n",
    "    \n",
    "    def __neg__(self):\n",
    "        result = Vector(len(self))\n",
    "        for i in range(len(self)):\n",
    "            result[i] = -self[i]\n",
    "        return result\n",
    "    \n",
    "    def __mul__(self, k):\n",
    "        result = Vector(len(self))\n",
    "        for i in range(len(self)):\n",
    "            result[i] = k*self[i]\n",
    "        return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<0, 5, 0, 0, 4>\n",
      "<0, 15, 0, 0, 12>\n"
     ]
    }
   ],
   "source": [
    "vector = Vector(5)\n",
    "vector[1] = 5\n",
    "vector[-1] = 4\n",
    "\n",
    "print(vector)\n",
    "print(vector*3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-2.13"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Vector:\n",
    "    \n",
    "    def __init__(self, d):                 \n",
    "        self._coords = [0]*d               \n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self._coords)         \n",
    "    \n",
    "    def __getitem__(self, j):              \n",
    "        return self._coords[j]\n",
    "    \n",
    "    def __setitem__(self, j, val):         \n",
    "        self._coords[j] = val           \n",
    "\n",
    "    def __add__(self, other):            \n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] + other[j]\n",
    "        return result\n",
    "    \n",
    "    def __sub__(self, other):\n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] - other[j]\n",
    "        return result\n",
    "    \n",
    "    def __eq__(self, other):                \n",
    "        return self._coords == other._coords \n",
    "    \n",
    "    def __ne__(self, other):\n",
    "        return not self == other\n",
    "    \n",
    "    def __str__(self):                     \n",
    "        return '<' + str(self._coords)[1:-1] + '>'\n",
    "    \n",
    "    def __neg__(self):\n",
    "        result = Vector(len(self))\n",
    "        for i in range(len(self)):\n",
    "            result[i] = -self[i]\n",
    "        return result\n",
    "    \n",
    "    def __mul__(self, k):\n",
    "        result = Vector(len(self))\n",
    "        for i in range(len(self)):\n",
    "            result[i] = k*self[i]\n",
    "        return result\n",
    "    \n",
    "    def __rmul__(self, k):\n",
    "        result = Vector(len(self))\n",
    "        for i in range(len(self)):\n",
    "            result[i] = k*self[i]\n",
    "        return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<0, 5, 0, 0, 4>\n",
      "<0, 15, 0, 0, 12>\n",
      "<0, 15, 0, 0, 12>\n"
     ]
    }
   ],
   "source": [
    "vector = Vector(5)\n",
    "vector[1] = 5\n",
    "vector[-1] = 4\n",
    "\n",
    "print(vector)\n",
    "print(vector*3)\n",
    "print(3*vector)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Vector:\n",
    "    \n",
    "    def __init__(self, d):                 \n",
    "        self._coords = [0]*d               \n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self._coords)         \n",
    "    \n",
    "    def __getitem__(self, j):              \n",
    "        return self._coords[j]\n",
    "    \n",
    "    def __setitem__(self, j, val):         \n",
    "        self._coords[j] = val           \n",
    "\n",
    "    def __add__(self, other):            \n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] + other[j]\n",
    "        return result\n",
    "    \n",
    "    def __sub__(self, other):\n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] - other[j]\n",
    "        return result\n",
    "    \n",
    "    def __eq__(self, other):                \n",
    "        return self._coords == other._coords \n",
    "    \n",
    "    def __ne__(self, other):\n",
    "        return not self == other\n",
    "    \n",
    "    def __str__(self):                     \n",
    "        return '<' + str(self._coords)[1:-1] + '>'\n",
    "    \n",
    "    def __neg__(self):\n",
    "        result = Vector(len(self))\n",
    "        for i in range(len(self)):\n",
    "            result[i] = -self[i]\n",
    "        return result\n",
    "    \n",
    "    def __mul__(self, other):\n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree') \n",
    "        else:\n",
    "            result = 0\n",
    "            for i in range(len(self)):\n",
    "                result += self[i]*other[i]\n",
    "        return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<1, 2, 3, 4, 5>\n",
      "<1, 4, 9, 16, 25>\n",
      "225\n"
     ]
    }
   ],
   "source": [
    "vectors = []\n",
    "\n",
    "vectors.append(Vector(5))\n",
    "vectors.append(Vector(5))\n",
    "\n",
    "for i in range(1, 6):\n",
    "    vectors[0][i-1] = i\n",
    "    vectors[1][i-1] = i**2\n",
    "\n",
    "print(vectors[0])\n",
    "print(vectors[1])\n",
    "print(vectors[0]*vectors[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-2.15"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Vector:\n",
    "    \n",
    "    def __init__(self, d = 0, list = []):\n",
    "        if d:\n",
    "            self._coords = d*[0]\n",
    "        elif list:\n",
    "            self._coords = []\n",
    "            for i in list:\n",
    "                self._coords.append(i)\n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self._coords)         \n",
    "    \n",
    "    def __getitem__(self, j):              \n",
    "        return self._coords[j]\n",
    "    \n",
    "    def __setitem__(self, j, val):         \n",
    "        self._coords[j] = val           \n",
    "\n",
    "    def __add__(self, other):            \n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] + other[j]\n",
    "        return result\n",
    "    \n",
    "    def __sub__(self, other):\n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] - other[j]\n",
    "        return result\n",
    "    \n",
    "    def __eq__(self, other):                \n",
    "        return self._coords == other._coords \n",
    "    \n",
    "    def __ne__(self, other):\n",
    "        return not self == other\n",
    "    \n",
    "    def __str__(self):                     \n",
    "        return '<' + str(self._coords)[1:-1] + '>'\n",
    "    \n",
    "    def __neg__(self):\n",
    "        result = Vector(len(self))\n",
    "        for i in range(len(self)):\n",
    "            result[i] = -self[i]\n",
    "        return result\n",
    "    \n",
    "    def __mul__(self, other):\n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree') \n",
    "        else:\n",
    "            result = 0\n",
    "            for i in range(len(self)):\n",
    "                result += self[i]*other[i]\n",
    "        return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<1, 2, 3>\n",
      "<1, 2, 3>\n",
      "<1, 2, 3>\n"
     ]
    }
   ],
   "source": [
    "vectors = []\n",
    "\n",
    "vectors.append(Vector(3))\n",
    "vectors.append(Vector(list=[1, 2, 3]))\n",
    "vectors.append(Vector(list=(1, 2, 3)))\n",
    "vectors[0][0] = 1\n",
    "vectors[0][1] = 2\n",
    "vectors[0][2] = 3\n",
    "\n",
    "for i in vectors:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-2.18"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 2 4 6 10 16 26 42\n"
     ]
    }
   ],
   "source": [
    "fp = FibonacciProgression(2, 2)\n",
    "fp.print_progression(8)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "R-2.19"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "要好多好多次，不运行了，容易崩。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-2.25"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Vector:\n",
    "    \n",
    "    def __init__(self, d = 0, list = []):\n",
    "        if d:\n",
    "            self._coords = d*[0]\n",
    "        elif list:\n",
    "            self._coords = []\n",
    "            for i in list:\n",
    "                self._coords.append(i)\n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self._coords)         \n",
    "    \n",
    "    def __getitem__(self, j):              \n",
    "        return self._coords[j]\n",
    "    \n",
    "    def __setitem__(self, j, val):         \n",
    "        self._coords[j] = val           \n",
    "\n",
    "    def __add__(self, other):            \n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] + other[j]\n",
    "        return result\n",
    "    \n",
    "    def __sub__(self, other):\n",
    "        if len(self) != len(other):\n",
    "            raise ValueError('dimensions must agree')       \n",
    "        result = Vector(len(self))\n",
    "        for j in range(len(self)):\n",
    "            result[j] = self[j] - other[j]\n",
    "        return result\n",
    "    \n",
    "    def __eq__(self, other):                \n",
    "        return self._coords == other._coords \n",
    "    \n",
    "    def __ne__(self, other):\n",
    "        return not self == other\n",
    "    \n",
    "    def __str__(self):                     \n",
    "        return '<' + str(self._coords)[1:-1] + '>'\n",
    "    \n",
    "    def __neg__(self):\n",
    "        result = Vector(len(self))\n",
    "        for i in range(len(self)):\n",
    "            result[i] = -self[i]\n",
    "        return result\n",
    "    \n",
    "    def __mul__(self, other):\n",
    "        if type(other) == int or type(other) == float:\n",
    "            result = Vector(len(self))\n",
    "            for i in range(len(self)):\n",
    "                result[i] = other*self[i]\n",
    "        else:\n",
    "            if len(self) != len(other):\n",
    "                raise ValueError('dimensions must agree') \n",
    "            else:\n",
    "                result = 0\n",
    "                for i in range(len(self)):\n",
    "                    result += self[i]*other[i]\n",
    "        return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<1, 2, 3>\n",
      "14\n",
      "<3, 6, 9>\n",
      "<1.5, 3.0, 4.5>\n"
     ]
    }
   ],
   "source": [
    "vectors = []\n",
    "\n",
    "vectors.append(Vector(list = [1, 2, 3]))\n",
    "vectors.append(Vector(list = [1, 2, 3]))\n",
    "\n",
    "print(vectors[0])\n",
    "print(vectors[0]*vectors[1])\n",
    "print(vectors[0]*3)\n",
    "print(vectors[0]*1.5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-2.26"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ReversedSequenceIterator:\n",
    "    \n",
    "    def __init__(self, sequence):\n",
    "        self._seq = sequence\n",
    "        self._k = 0\n",
    "    \n",
    "    def __next__(self):\n",
    "        self._k -= 1\n",
    "        if self._k >= -len(self._seq):              ## 这里要求输入的类实例实现了__len__方法\n",
    "            return self._seq[self._k]               ## 这里要求输入的类实例实现了__getitem__方法\n",
    "        else:\n",
    "            return StopIteration()\n",
    "        \n",
    "    def __iter__(self):\n",
    "        return self"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6\n",
      "5\n",
      "4\n",
      "3\n",
      "2\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "sequence = ReversedSequenceIterator([1, 2, 3, 4, 5, 6])\n",
    "for i in range(6):\n",
    "    print(next(sequence))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-2.27"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "特殊方法`__getitem__`和`__len__`的存在，会使类变得`iterable`，并且也能支持`in`关键字的使用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.0\n"
     ]
    }
   ],
   "source": [
    "start = time.process_time()\n",
    "1 in Range(10000000)            ## in需要特殊方法__contains__的支持，Range虽然没有，但是有__len__和__getitem__也足够了，会自己调用\n",
    "stop = time.process_time()\n",
    "print(stop - start)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.90625\n"
     ]
    }
   ],
   "source": [
    "start = time.process_time()\n",
    "9999999 in Range(10000000)                     \n",
    "stop = time.process_time()\n",
    "print(stop - start)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "显然自动提供的`__contains__`方法是自动从第一个元素开始迭代的，因此使用二分查找重新编写`__contains__`可能更好。因为序列也是有序的。或者直接根据start、stop和step来计算即可。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运用step："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Range:\n",
    "    \n",
    "    def __init__(self, start, stop=None, step = 1):\n",
    "        if step == 0:\n",
    "            raise ValueError('step cannot be 0')\n",
    "        if stop is None:\n",
    "            start, stop = 0, start\n",
    "        self._length = max(0, (stop - start + step - 1)//step)         \n",
    "        self._start = start\n",
    "        self._stop = stop\n",
    "        self._step = step\n",
    "    \n",
    "    def __len__(self):\n",
    "        return self._length\n",
    "    \n",
    "    def __getitem__(self, k):\n",
    "        if k < 0:\n",
    "            k += len(self)\n",
    "        if not 0 <= k < self._length:\n",
    "            raise IndexError('index out of range')\n",
    "        return self._start + k*self._step   \n",
    "    \n",
    "    def __contains__(self, k):\n",
    "        return (k-self._start)%self._step == 0 and self._start <= k < self._stop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.0\n",
      "0.0\n"
     ]
    }
   ],
   "source": [
    "start = time.process_time()\n",
    "1 in Range(10000000)                     \n",
    "stop = time.process_time()\n",
    "print(stop - start)\n",
    "\n",
    "start = time.process_time()\n",
    "9999999 in Range(10000000)                     \n",
    "stop = time.process_time()\n",
    "print(stop - start)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运用二分查找："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Range:\n",
    "    \n",
    "    def __init__(self, start, stop=None, step = 1):\n",
    "        if step == 0:\n",
    "            raise ValueError('step cannot be 0')\n",
    "        if stop is None:\n",
    "            start, stop = 0, start\n",
    "        self._length = max(0, (stop - start + step - 1)//step)         \n",
    "        self._start = start\n",
    "        self._stop = stop\n",
    "        self._step = step\n",
    "    \n",
    "    def __len__(self):\n",
    "        return self._length\n",
    "    \n",
    "    def __getitem__(self, k):\n",
    "        if k < 0:\n",
    "            k += len(self)\n",
    "        if not 0 <= k < self._length:\n",
    "            raise IndexError('index out of range')\n",
    "        return self._start + k*self._step   \n",
    "    \n",
    "    def __contains__(self, k):\n",
    "        if k < self._start or k >= self._stop:\n",
    "            return False\n",
    "        else:    \n",
    "            i = 0\n",
    "            j = len(self)-1\n",
    "            while i <= j:\n",
    "                mid_index = int((i+j)/2)\n",
    "                mid = self[mid_index]\n",
    "                if mid > k:\n",
    "                    j = mid_index-1\n",
    "                elif mid < k:\n",
    "                    i = mid_index+1\n",
    "                else:\n",
    "                    return True\n",
    "            return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.0\n",
      "0.0\n"
     ]
    }
   ],
   "source": [
    "start = time.process_time()\n",
    "1 in Range(10000000)                     \n",
    "stop = time.process_time()\n",
    "print(stop - start)\n",
    "\n",
    "start = time.process_time()\n",
    "9999999 in Range(10000000)                     \n",
    "stop = time.process_time()\n",
    "print(stop - start)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-2.28"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "class PredatoryCreditCard(CreditCard):\n",
    "    \n",
    "    def __init__(self, customer, bank, acnt, limit, apr):\n",
    "        super().__init__(customer, bank, acnt, limit)           \n",
    "        self._apr = apr\n",
    "        self._chargenum = 0\n",
    "    \n",
    "    def charge(self, price):  \n",
    "        self._chargenum += 1\n",
    "        success = super().charge(price)\n",
    "        if not success:\n",
    "            self._balance -= 5\n",
    "        if self._chargenum > 10:\n",
    "            self._balance -= 1\n",
    "            print('Charge $1')\n",
    "        return success\n",
    "    \n",
    "    def process_month(self):\n",
    "        if self._balance > 0:\n",
    "            monthly._factor = pow(1 + self._apr, 1/12)\n",
    "            self._balance *= monthly._factor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Charge $1\n",
      "Charge $1\n",
      "Charge $1\n",
      "Charge $1\n",
      "Charge $1\n"
     ]
    }
   ],
   "source": [
    "card =  PredatoryCreditCard('John Bowman', 'California Savings', '5391 0375 9387 5309', 2500, 1000)\n",
    "\n",
    "for i in range(15):\n",
    "    card.charge(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-2.29和C-2.30跳过。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-2.31"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyProgression(Progression):\n",
    "    def __init__(self, a = 2, b = 200):\n",
    "        super().__init__(a)\n",
    "        self._b = b\n",
    "    \n",
    "    def _advance(self):\n",
    "        self._current, self._b = self._b, abs(self._current-self._b)          ## 与斐波那契数列差不多"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 200 198 2 196 194 2 192 190 2\n"
     ]
    }
   ],
   "source": [
    "myprogression = MyProgression()\n",
    "\n",
    "myprogression.print_progression(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C-2.32"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyProgression(Progression):\n",
    "    def __init__(self, a = 65536):\n",
    "        super().__init__(a)\n",
    "    \n",
    "    def _advance(self):\n",
    "        self._current = self._current**0.5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "65536 256.0 16.0 4.0 2.0 1.4142135623730951 1.189207115002721 1.0905077326652577 1.0442737824274138 1.0218971486541166\n"
     ]
    }
   ],
   "source": [
    "myprogression = MyProgression()\n",
    "\n",
    "myprogression.print_progression(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "P-2.33"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "多项式求导——>调用numpy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "P-2.34"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于列表或者元组，如果元素是多维的，可以使用`sorted`指定按照每一个元素的哪一维进行排序。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def alphabet(string):\n",
    "    string_unique = set(string)\n",
    "    string_dict = {a: string.count(a) for a in string_unique if a.isalpha()}\n",
    "    string_dict = dict(sorted(string_dict.items(), key=lambda x : x[1], reverse=True))  ## sorted按照每个元素x的索引为1的元素进行排序\n",
    "    \n",
    "    plt.figure(figsize = (8, 6))\n",
    "    plt.bar(x=string_dict.keys(), height=string_dict.values(), width=0.6)\n",
    "    plt.ylim(0, max(string_dict.values())+1)\n",
    "    \n",
    "    return None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 576x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 576x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "alphabet('aaaaabbbcccciiiiiiiook')\n",
    "alphabet('a, ; sodsjkjsjjjjdsdjf')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "P-2.35\n",
    "\n",
    "跳过"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
